class PColorView extends View {
  
  Slice env;
  Statevar var;
  int K,M;
  color[] cmap = warmrainbow();
  float dataMin, dataMax;
  int[] lastKM;
  boolean selectable = false;
  float rescaleFactor = 1;
  String varUnits = "";
  
  
  PColorView() {
    shortname = "section";
  }
  
  PColorView(Slice env, String varname, float dataMin, float dataMax, float rescaleFactor, String newUnits) {
    this(env, varname, dataMin, dataMax);
    this.rescaleFactor = rescaleFactor;
    varUnits = newUnits;
  }

  PColorView(Slice env, String varname, float dataMin, float dataMax) {
    shortname = "section";
    this.env = env;
    this.var = env.getVar(varname);
    this.K = env.K;
    this.M = env.M;
    this.dataMin = dataMin;
    this.dataMax = dataMax;
  }
  
  
  void define() {
    ax.styles = styles;
    ax.setXRange(env.x_u[0]/1000., env.x_u[M]/1000.); // measure x axis in km
    ax.setYRange(env.z_w[0], env.z_w[K]);
    setXLabels(new float[] {env.x_u[0]/1000., env.x_u[M]/1000.}, "km");
    setZLabels(new float[] {env.z_w[0], env.z_w[K]}, "m");
    ax.largeTopLabel = true;
    ax.axesOn = false;
    // adjustments to screen position
    ax.x0 += 70;
    ax.wd -= 200;
    ax.y0 += 50;
    ax.ht -= 80;
    if (ax.width()/float(M) > 3 * ax.height()/float(K)) { // if too stretched horizontally: average cell with an aspect ratio > 3:1
      ax.wd = ax.height()/float(K) * 3 * M;
    }
    float[] x_u_km = new float[env.M+1];
    for (int m=0; m<env.M+1; m++) x_u_km[m] = env.x_u[m]/1000.;
    ax.createCells(x_u_km, env.z_w);
    for (int m=0; m<M; m++) {
      for (int k=0; k<env.kbot[m]; k++) {
        ax.cells[k][m].faceCol = color(255,0);
      }
    }    
    mapColor(dataMin, dataMax, cmap);
    setVarLabel();
    if (selectable) {
      for (int m=0; m<M; m++) {
        for (int k=env.kbot[m]; k<K; k++) {
          ax.cells[k][m].selectable = true;
        }
      }
    }
  }

  void setXLabels(float[] labels, String units) {
    ax.setLabels("top", "", labels);
    ax.topTickLabels[ax.topTickLabels.length-1] += " " + units;
  }
  
  void setZLabels(float[] labels, String units) {
    ax.setLabels("left", "", labels);
    ax.leftTickLabels[0] += " " + units;
  }
  
  void setVarLabel() {
    ax.topLabel = var.name.toUpperCase();
    ax.topLabel += " (" + ax.cells[K-1][M-1].zdmin + " - " + ax.cells[K-1][M-1].zdmax + " " + varUnits + ")";
  }
  
  
  void mapColor(float zdmin, float zdmax, color[] cmap) {
    for (int m=0; m<M; m++) {
      for (int k=env.kbot[m]; k<K; k++) {
        ax.cells[k][m].mapColor(zdmin, zdmax, cmap);
      }
    }
  }


  boolean update() {
    boolean result = false;
    for (int m=0; m<M; m++) {
      for (int k=env.kbot[m]; k<K; k++) {
        boolean clicked = ax.cells[k][m].selectable && ax.cells[k][m].update();
        if (clicked) {
          result = true;
          lastKM = new int[] {k, m};
        }
      }
    }
    return result;
  }
  
  
  void draw() {
    for (int m=0; m<M; m++) {
      for (int k=env.kbot[m]; k<K; k++) {
        ax.cells[k][m].faceCol = ax.cells[k][m].getMappedColor(var.current[env.km2ind(k,m)]*rescaleFactor);
      }
    }
    ax.draw();
    ax.drawOnTop();
    if (ax.over()) {
      int[] km = ax.overWhich();
      if (km[0] != -1) {
        if (km[0] >= env.kbot[km[1]]) {
          pushStyle();
          fill(0);
          styles.setFont(styles.normalFontSize);
          String value = "" + (round(var.current[env.km2ind(km[0],km[1])]*rescaleFactor*100.)/100.) + " " + varUnits;
          text(value, mouseX + 4, mouseY - styles.normalFontSize - 4);
          popStyle();
        }
      }
    }
  }
  
  
  boolean offerMousePress() {
    if (!selectable) return false;
    for (int m=0; m<M; m++) {
      for (int k=env.kbot[m]; k<K; k++) {
        if (ax.cells[k][m].offerMousePress()) return true;
      }
    }
    return false;
  }
  
  
}



// ----------------------------------------------------------------------------------------



class PColorNetworkSwitcherView extends View {

  Slice env;
  HashMap pcolors = new HashMap();
  NetworkView network;
  PColorView currentPColor = null;
  boolean longnamesInToolbar = true;
  
  PColorNetworkSwitcherView() {}
  
  PColorNetworkSwitcherView(Slice env, NetworkView network) {
    shortname = "section/network";
    this.env = env;
    this.network = network;
    if (network != null) network.selectable = true;
  }
  
  PColorView addVar(String varname, float dataMin, float dataMax, float rescaleFactor, String newUnits) {
    PColorView pcv = new PColorView(env, varname, dataMin, dataMax, rescaleFactor, newUnits);
    pcv.selectable = true;
    pcolors.put(varname, pcv);
    if (currentPColor==null) currentPColor = pcv;
    return pcv;
  }

  PColorView addVar(String varname, float dataMin, float dataMax) {
    PColorView pcv = new PColorView(env, varname, dataMin, dataMax);
    pcv.selectable = true;
    pcolors.put(varname, pcv);
    if (currentPColor==null) currentPColor = pcv;
    return pcv;
  }
  
  void wakeup(Gui gui) {
    super.wakeup(gui);
    if (network != null) {
      network.wakeup(gui);
      network.ax.x0 += network.ax.width()/2.;
      network.ax.wd /= 2.;
      network.ax.y0 += network.ax.height()/2.;
      network.ax.ht /= 2; 
    }
    toolbar = new Toolbar(0, 0, width, styles); // the gui will place it in the right place on screen
    toolbar.addTextLabel("variables");
    Iterator i = pcolors.values().iterator();
    while (i.hasNext()) {
      PColorView pcv = ((PColorView) i.next());
      pcv.wakeup(gui);
      if (longnamesInToolbar) {
        toolbar.addTextButton(pcv.var.name);
      } else {
        toolbar.addTextButton(pcv.var.shortname);        
      }
    }
    if (toolbar.elements.length <= 2) toolbar.hidden = true; // don't show the toolbar if it's just the label + one button
  }
  
  boolean offerMousePress() {
    boolean captured = false;
    if (network != null) captured = network.offerMousePress();
    if (!captured) captured = currentPColor.offerMousePress();
    if (!captured) captured = toolbar.offerMousePress();
    return captured;
  }
  
  boolean update() {
    boolean result = false;
    if (network != null) {
      boolean clicked = network.update();
      if (clicked) {
        selectVar(network.lastVar);
        result = true;
      }
    }
    boolean clicked = currentPColor.update();
    if (clicked) {
      selectCell(currentPColor.lastKM);
      result = true;
    }
    clicked = toolbar.update();
    if (clicked) {
      String varname = toolbar.lastUpdated;
      if (longnamesInToolbar) varname = longname2shortname(varname);
      selectVar(varname);
      result = true;
    }
    return result;
  }
  
  String longname2shortname(String longname) {
    for (int i=0; i<env.vars.length; i++) {
      if (env.vars[i].name.equals(longname)) return env.vars[i].shortname;
    }
    return null;
  }
  
  String shortname2longname(String shortname) {
    for (int i=0; i<env.vars.length; i++) {
      if (env.vars[i].shortname.equals(shortname)) return env.vars[i].name;
    }
    return null;
  }

  void selectVar(String varname) {    
    PColorView chosenPColor = (PColorView) pcolors.get(varname);    // switch to the correct pcolor
    if (chosenPColor == null) return;                     // if the dot corresponds to a var that doesn't have an associated pcolor, do nothing
    currentPColor = chosenPColor;
    if (network != null) {
      for (int i=0; i<network.dots.length; i++) {         // deselect other dots and select the new one
        network.dots[i].alwaysAwake = false;
      }
      Dot D = network.findDot(varname);
      if (D != null) D.alwaysAwake = true;
      selectCell(env.ind2km(network.currentCell));       // make sure the correct cell is selected
    }
    toolbar.deselect();
    if (longnamesInToolbar) {
      toolbar.select(shortname2longname(varname));
    } else {
      toolbar.select(varname);
    }
  }
  
  void selectCell(int[] km) {
    for (int m=0; m<currentPColor.M; m++) {              // deselect other cells in the pcolor and select the new one
      for (int k=env.kbot[m]; k<currentPColor.K; k++) {
        currentPColor.ax.cells[k][m].alwaysAwake = false;
      }
    }
    currentPColor.ax.cells[km[0]][km[1]].alwaysAwake = true;
    int k = env.km2ind(km[0],km[1]);                  // switch the cell # in the network diagram
    if (network != null) network.currentCell = k;
  }
  
  
  void draw() {
    currentPColor.draw();
    if (network != null) network.draw();
  }

}
